﻿using Application.Commons.Data;
using FrameworkCore.Interfaces;
using FrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Query;
using System.Linq.Expressions;

namespace Infrastructure.Persistence;

public class EfCoreProvider : BaseDataProvider, IAiBLSmartEduDataProvider
{
    private readonly EfCoreDbContext _dbContext;
    private readonly IGenerateIdService _generateIdService;
    public EfCoreProvider(
        EfCoreDbContext dbContext,
        IGenerateIdService generateIdService)
    {
        _dbContext = dbContext;
        _generateIdService = generateIdService;
    }

    #region 增删改
    /// <summary>
    /// 将记录插入表中。返回带有自增主键的插入实体。
    /// </summary>
    /// <typeparam name="TEntity">要插入的实体</typeparam>
    /// <param name="entity">实体类型</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>
    /// 表示异步操作的任务
    /// 任务结果包含插入的实体
    /// </returns>
    public override async Task<TEntity> InsertEntityAsync<TEntity>(
        TEntity entity,
        CancellationToken cancellationToken = default)
    {
        if (entity.Id == 0) 
        {
            entity.Id = _generateIdService.GenerateIdAsLong();
        }
        await _dbContext!.Set<TEntity>().AddAsync(entity);
        await SaveChangesAsync(cancellationToken);
        return entity;
    }

    /// <summary>
    /// 将记录插入表中。返回带有自增主键的插入实体。
    /// </summary>
    /// <param name="entity">要插入的实体</param>
    /// <typeparam name="TEntity">实体类型</typeparam>
    /// <returns>插入的实体</returns>
    public override TEntity InsertEntity<TEntity>(TEntity entity)
    {
        if (entity.Id == 0)
        {
            entity.Id = _generateIdService.GenerateIdAsLong();
        }
        _dbContext!.Set<TEntity>().Add(entity);
        SaveChanges();
        return entity;
    }

    /// <summary>
    /// 使用实体参数的值更新表中的记录。
    /// 根据主键值匹配实体确定要更新的记录。
    /// </summary>
    /// <param name="entity">带有更新数据的实体</param>
    /// <typeparam name="TEntity">实体类型</typeparam>
    public override void UpdateEntity<TEntity>(TEntity entity)
        => _dbContext!.Set<TEntity>().Update(entity);

    /// <summary>
    /// 使用实体参数的值更新表中的记录。
    /// 根据主键值匹配实体确定要更新的记录。
    /// </summary>
    /// <param name="entities">带有更新数据的实体集合</param>
    /// <typeparam name="TEntity">实体类型</typeparam>
    public override void UpdateEntities<TEntity>(IEnumerable<TEntity> entities)
        => _dbContext!.Set<TEntity>().UpdateRange(entities);

    /// <summary>
    /// 根据条件在表中执行批量修改记录操作。
    /// </summary>
    /// <typeparam name="TEntity">实体类型</typeparam>
    /// <param name="setPropertyCalls">修改的列</param>
    /// <param name="predicate">用于修改每个元素条件的函数</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// 表示异步操作的任务
    /// 任务结果包含修改的记录数
    /// <returns></returns>
    public override async Task<int> BulkUpdateEntitiesAsync<TEntity>(
        Expression<Func<SetPropertyCalls<TEntity>, SetPropertyCalls<TEntity>>> setPropertyCalls,
        Expression<Func<TEntity, bool>> predicate,
        CancellationToken cancellationToken = default)
        => await _dbContext!.Set<TEntity>().Where(predicate).ExecuteUpdateAsync(setPropertyCalls, cancellationToken);

    /// <summary>
    /// 根据条件在表中执行批量修改记录操作。
    /// </summary>
    /// <typeparam name="TEntity">实体类型</typeparam>
    /// <param name="setPropertyCalls">修改的列</param>
    /// <param name="predicate">用于修改每个元素条件的函数</param>
    /// 修改的记录数
    /// <returns></returns>
    public override int BulkUpdateEntities<TEntity>(
        Expression<Func<SetPropertyCalls<TEntity>, SetPropertyCalls<TEntity>>> setPropertyCalls,
        Expression<Func<TEntity, bool>> predicate)
        => _dbContext!.Set<TEntity>().Where(predicate).ExecuteUpdate(setPropertyCalls);

    /// <summary>
    /// 删除表中的记录。要删除的记录通过与实体对象的主键值匹配来确定。
    /// </summary>
    /// <param name="entity">删除操作的实体</param>
    /// <typeparam name="TEntity">实体类型</typeparam>
    public override void DeleteEntity<TEntity>(TEntity entity)
        => _dbContext!.Set<TEntity>().Remove(entity);

    /// <summary>
    /// 在表中执行批量删除记录操作。
    /// </summary>
    /// <param name="entities">要删除的实体集合</param>
    /// <typeparam name="TEntity">实体类型</typeparam>
    public override void BulkDeleteEntities<TEntity>(IList<TEntity> entities)
        => _dbContext!.Set<TEntity>().RemoveRange(entities);

    /// <summary>
    /// 根据条件在表中执行批量删除记录操作。
    /// </summary>
    /// <param name="predicate">用于修改每个元素条件的函数</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <typeparam name="TEntity">实体类型</typeparam>
    /// <returns>
    /// 表示异步操作的任务
    /// 任务结果包含删除的记录数
    /// </returns>
    public override async Task<int> BulkDeleteEntitiesAsync<TEntity>(
        Expression<Func<TEntity, bool>> predicate,
        CancellationToken cancellationToken = default)
    => await _dbContext!.Set<TEntity>().Where(predicate).ExecuteDeleteAsync(cancellationToken);

    /// <summary>
    /// 根据条件在表中执行批量删除记录操作。
    /// </summary>
    /// <param name="predicate">用于测试每个元素条件的函数</param>
    /// <typeparam name="TEntity">实体类型</typeparam>
    /// <returns>
    /// 删除的记录数
    /// </returns>
    public override int BulkDeleteEntities<TEntity>(
        Expression<Func<TEntity, bool>> predicate)
        => _dbContext!.Set<TEntity>().Where(predicate).ExecuteDelete();


    /// <summary>
    /// 对实体集合执行批量插入操作。
    /// </summary>
    /// <param name="entities">要插入的实体集合</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <typeparam name="TEntity">实体类型</typeparam>
    /// <returns>表示异步操作的任务</returns>
    public override async Task BulkInsertEntitiesAsync<TEntity>(
        IEnumerable<TEntity> entities,
        CancellationToken cancellationToken = default)
    {
        foreach (var entity in entities) 
        {
            if (entity.Id == 0)
            {
                entity.Id = _generateIdService.GenerateIdAsLong();
            }
        }
        await _dbContext!.Set<TEntity>().AddRangeAsync(entities);
    }

    /// <summary>
    /// 对实体集合执行批量插入操作。
    /// </summary>
    /// <param name="entities">要插入的实体集合</param>
    /// <typeparam name="TEntity">实体类型</typeparam>
    public override void BulkInsertEntities<TEntity>(IEnumerable<TEntity> entities)
    {
        foreach (var entity in entities)
        {
            if (entity.Id == 0)
            {
                entity.Id = _generateIdService.GenerateIdAsLong();
            }
        }
        _dbContext!.Set<TEntity>().AddRange(entities);
    }

    /// <summary>
    /// 保存
    /// </summary>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns></returns>
    public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
        => await _dbContext!.SaveChangesAsync(cancellationToken);

    /// <summary>
    /// 保存
    /// </summary>
    /// <returns></returns>
    public override int SaveChanges() => _dbContext!.SaveChanges();

    #endregion

    #region 查询
    public override IQueryable<TEntity> Query<TEntity>()
    {
        return _dbContext!.Set<TEntity>()
            .AsNoTracking()
            .AsQueryable();
    }
    #endregion
}
